/* Compile me with:  jflex mini.lex  */
package lex;

%%

%class Scanner

%type Token

%{
Token tok(String tag) { 
	return new Token(tag, yycolumn+1, yyline+1, yytext());
}
%}
	
%column

INT = (0)|[1-9][0-9]*
ID = [a-z][a-z0-9A-Z\_]*
CLASS_ID = [A-Z][a-z0-9A-Z\_]*
DQUOTE = "\""
VALID_STRING_CHARS=[ !#-Z_-~] | \\t | \\n | \\\\ | \[ | \] | \^ | \\(\\\\)*\"
VALID_STRING = \"{VALID_STRING_CHARS}*\"
INVALID_STRING = {DQUOTE} (\")*

COMMENT = ("#" .*) | ("//" .*)
MUTLILINE_COMMENT = "/*" ~("*/")
OPEN_MUTLILINE_COMMENT = "/*" ~([^(\*/)])
 
CLASS = class
EXTENDS = extends
STATIC = static
VOID = void
INT_TYPE = int
BOOLEAN_TYPE = boolean
STRING_TYPE = string
MULTIPLY = \*
DIVIDE = \/
MOD = %
PLUS = \+
MINUS = \-
RETURN = return
IF = if
ELSE = else
WHILE = while
BREAK = break
CONTINUE = continue
THIS = this
NEW = new
LENGTH = length
TRUE = true
FALSE = false
NULL = null

SEMICOLON  = ;
COMMA = ,
LESS_THAN  = <
LESS_THAN_EQ = <=
BIGGER_THAN = >
BIGGER_THAN_EQ = >=
EQ = ==
NOTEQ = \!=
AND = &&
OR = \|\|
ASSIGN = =
NOT = \!
LEFT_BRACK = \[
RIGHT_BRACK = \]
LEFT_PARAN = \(
RIGHT_PARAN = \)
LEFT_CURLY = \{
RIGHT_CURLY = \}
FULL_STOP = \.


%%

{INT}       { return tok("INTEGER"); }

{MUTLILINE_COMMENT} {yyline += yytext().split("\r\n|\r|\n").length-1;}
{OPEN_MUTLILINE_COMMENT} {throw new Error(String.format("%d:%d : lexical error; unterminated comment",yyline + 1, yycolumn + 1));}
{VALID_STRING} {return tok("STRING"); }
{INVALID_STRING}       { throw new Error(String.format("%d:%d : lexical error; malformed string literal",yyline + 1, yycolumn + 1)); }

{CLASS} 	{ return tok ("class"); }
{EXTENDS} 	{ return tok ("extends"); }
{STATIC} 	{ return tok ("static"); }
{VOID} 	{ return tok ("void"); }
{INT_TYPE} 	{ return tok ("int"); }
{BOOLEAN_TYPE} 	{ return tok ("boolean"); }
{STRING_TYPE} 	{ return tok ("string"); }
{RETURN} 	{ return tok ("return"); }
{IF} 	{ return tok ("if"); }
{ELSE} 	{ return tok ("else"); }
{WHILE} 	{ return tok ("while"); }
{BREAK} 	{ return tok ("break"); }
{CONTINUE} 	{ return tok ("continue"); }
{THIS} 	{ return tok ("this"); }
{NEW} 	{ return tok ("new"); }
{LENGTH} 	{ return tok ("length"); }
{TRUE} 	{ return tok ("true"); }
{FALSE} 	{ return tok ("false"); }
{NULL} 	{ return tok ("null"); }
{LEFT_BRACK} { return tok("[");}
{RIGHT_BRACK} { return tok("]");}
{LEFT_PARAN}	{ return tok("(");}
{RIGHT_PARAN}	{ return tok(")");}
{LEFT_CURLY}	{ return tok("{");}
{RIGHT_CURLY}	{ return tok("}");}

{SEMICOLON}	{return tok (";");}
{LESS_THAN}		{return tok ("<");}
{LESS_THAN_EQ}	{return tok ("<=");}
{BIGGER_THAN}	{return tok (">");}
{BIGGER_THAN_EQ}	{return tok (">=");}

{MOD}		{return tok("%");}
{EQ}		{return tok("==");}
{ASSIGN}	{return tok("=");}
{NOTEQ}		{return tok("!=");}
{AND}		{return tok("&&");}
{OR}		{return tok("||");}
{NOT}		{return tok("!");}

{MULTIPLY} 	{return tok("*");}
{DIVIDE} 	{return tok("/");}
{PLUS}	{return tok("+");}
{MINUS}	{return tok("-");}

{COMMA}		{return tok (",");}
{FULL_STOP}		{ return tok(".");}

{CLASS_ID}        { return tok("CLASS_ID"); }
{ID}        { return tok("ID"); }

(\r|\n|\r\n) { yyline++; }
{COMMENT} | [ ]         { /* nothing; skip */ }

^_          { throw new Error(String.format("%d:%d : lexical error; an identifier cannot start with \'%s\'",yyline + 1, yycolumn + 1, yytext())); }
.           { throw new Error(String.format("%d:%d : lexical error; invalid character \'%s\'",yyline + 1, yycolumn + 1, yytext())); }
